home *** CD-ROM | disk | FTP | other *** search
- #pragma linesize(132) /* listing linewidth = 132 */
-
- /* hpgl1.c */
- /* This code Copyright 1991, 1992, Robert C. Becker, Lantern Systems */
-
-
- /* rev. E 8/16/92
-
- Added solid line fill type to filled rectangles. Also added new window
- window clipper. It was needed for solid fill type because we do direct
- access to pw_wrt_line () in the graphix library. This routine also cleaned
- up some of the clipping code in showhpgl.c and fixed a few bugs related to
- drawing outside the P1/P2 hard clip if IW was defined larger than the
- hard clip border
- */
-
- /* rev. D 8/13/92
-
- Relocated some code from hpgl1.c to hpgl2.c to make file sizes more
- equal and reduce compile time of hpgl1.c . */
-
- /* Rev. C. 8/8/92
-
- Found and fixed bugs in tick mark calculation and filled rectangles. The tick
- mark bug manifested itself as not resizing tick sizes when P1/P2 changed. Part
- of the fix is in showhpgl.c . Added recalc_ticksize ().
-
- Found and fixed bug in filled rectangle drawing routines. Fixed logic errors
- in fill_type () which assigned the wrong units when default spacing was in
- effect. fill_rect () attempted to draw in plotter units even if user unit
- scaling was in effect.
- */
-
- /* Rev. B. 8/2/92
-
- Found a bug in tick mark drawing routines. In order to simplify the need
- to draw in a consistent size unit based on the P1/P2 spacings, the tick size
- was calculated in GDU's and the drawing mode was changed from UDU's to GDU's.
- This, unfortunately, reset the clip border to the hardclip limit, instead of
- the UDU border and allowed ticks to be drawn outside the soft clip border.
- calc_ticksize () has been changed to calculate tick sizes in plotter units,
- and two other variables (uu_2_pux, uu_2_puy) which are calculated every time
- set_scale () is called convert from user units to ploter units depending on
- scaling = ON/OFF.
- */
-
- /* Rev. A. */
-
- /* This file contains the following functions:
-
- arc_3pt ()
- calc_ticksize ()
- chord_t ()
- circle ()
- cot ()
- draw_xtick ()
- draw_ytick ()
- draw_rect ()
- fill_rect ()
- fill_type ()
- fix_hatch ()
- init_fills ()
- new_plot ()
- plotted_on ()
- print_error ()
- recalc_ticksize ()
- tick_length ()
- velocity_sel ()
-
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <float.h>
- #include "graph.h" /* this must preceed hpgl.h */
- #include "mscio.h" /* header for pc_wrt_line () */
- #include "gstructs.h" /* header file for library structures */
- #include "hpgl.h"
-
- extern struct hp_misc __gr_msc__; /* library struct */
-
- extern struct clip_border hpgl_clip;
- extern int my_pen;
- extern int scaling;
- extern double p1x, p1y, p2x, p2y;
- extern int chord_type, p_status, symbol_mode;
- extern double uu_2_pux, uu_2_puy;
- extern char symbol;
- extern int debugging;
-
- static void fill_rect (double, double, double, double, double, double);
- static double cot ( double );
- static void solid_rect ( double, double, double, double );
- static int code ( int, int);
-
- static char copyright[] = "Copyright 1991, 1992, Robert C. Becker, Lantern Systems";
-
- struct poly_fills
- {
- int mode;
- double opt1, opt2;
- double alt_opt1;
- };
-
- static struct poly_fills fill_code [6]; /* hold values for types 1, 2, 3, 4, 10, 11 */
- /* values for these type stored in this order in struct array */
-
- struct tick
- {
- double tnx, tny, tpx, tpy, tn, tp;
- /* x, y tick negative & positive lengths in plotter units; tx, ty in % */
- };
-
- static struct tick ticksize;
-
- static int select_fill; /* last fill type selected */
- static double anchor_x, anchor_y; /* corner anchors for fill types */
- static int dirty_plot; /* flag to mark if plot has been plotted on yet */
-
- /*--------------------------------------*/
-
- void velocity_sel (FILE *infile)
- {
- double x;
-
- DB (printf ("VS\n");)
- if (get_val (infile, &x)) /* optional speed argument: not used */
- {
- get_val (infile, &x); /* optional pen # argument: not used */
- }
- return;
- }
-
- /*--------------------------------------*/
-
- void tick_length (FILE *infile)
- {
- double tp, tn;
-
- tp = DEF_TICK;
- tn = DEF_TICK; /* default tick lengths */
- if ( get_val (infile, &tp)) /* got one value: try for two */
- {
- if (!get_val (infile, &tn)) tn = 0.0; /* if only have one value, tn = 0 */
- }
- calc_ticksize (tp, tn);
-
- return;
- }
-
- /*--------------------------------------*/
-
- void recalc_ticksize ( void )
- {
-
- /* force recalculation of ticksize when P1/P2 change */
- calc_ticksize (ticksize.tp, ticksize.tn);
-
- return;
- }
-
- /*--------------------------------------*/
-
- void calc_ticksize (double tp, double tn)
- {
-
- tp = MAX (-100.0, (MIN (100.0, tp)));
- tn = MAX (-100.0, (MIN (100.0, tn))); /* limit tick size to +/- 100% */
-
- ticksize.tp = tp;
- ticksize.tn = tn; /* save tick lengths */
-
- /* calculate tick lengths (plotter units) for x- and y-axes */
-
- ticksize.tpx = tp * fabs (p2x - p1x) / 100.0;
- ticksize.tpy = tp * fabs (p2y - p1y) / 100.0;
- ticksize.tnx = tn * fabs (p2x - p1x) / 100.0;
- ticksize.tny = tn * fabs (p2y - p1y) / 100.0;
- /* P1, P2 are in mils (plotter units) */
-
- DB (printf ("calc_ticksize: tpx = %lf, tnx = %lf, tpy = %lf, tny = %lf\n", \
- ticksize.tpx, ticksize.tnx, ticksize.tpy, ticksize.tny);)
-
- return;
- }
-
- /*--------------------------------------*/
-
- void draw_xtick (void)
- {
- double x_1, y_1;
- double ystart, ystop; /* local variables */
-
- /* move relative to current position. Convert plotter units to user
- units if required */
-
- ystart = -ticksize.tny;
- ystop = ticksize.tpy; /* start & stop points in plotter units */
-
- if (scaling == ON) /* start & stop points in user units */
- {
- ystart = -ticksize.tny * uu_2_puy;
- ystop = ticksize.tpy * uu_2_puy;
- }
-
- where (&x_1, &y_1); /* get starting position */
-
- DB (printf ("draw_xtick: scaling = %d, ystart = %lf, ystop = %lf\n", \
- scaling, ystart, ystop);)
-
- rmove (0.0, ystart); /* move relative to current position */
- rdraw (0.0, ystop); /* draw vertical tick mark */
- move (x_1, y_1); /* re-establish original position */
- plotted_on (1); /* we drew something on this plot */
-
- return;
- }
-
- /*--------------------------------------*/
-
- void draw_ytick (void)
- {
- double x_1, y_1;
- double xstart, xstop; /* local variables */
-
- /* move relative to current position. Convert plotter units to user
- units if required */
-
- xstart = -ticksize.tnx;
- xstop = ticksize.tpx; /* start & stop points in plotter units */
-
- if (scaling == ON) /* start & stop points in user units */
- {
- xstart = -ticksize.tnx * uu_2_pux;
- xstop = ticksize.tpx * uu_2_pux;
- }
-
- where (&x_1, &y_1);
-
- DB (printf ("draw_ytick: scaling = %d, xstart = %lf, xstop = %lf\n", \
- scaling, xstart, xstop);)
-
- rmove (xstart, 0.0);
- rdraw (xstop, 0.0); /* draw horizontal tick mark */
- move (x_1, y_1); /* re-establish original position */
- plotted_on (1); /* we drew something on this plot */
-
- return;
- }
-
- /*--------------------------------------*/
-
- void print_error (char *instr, int type)
- {
-
- if (!debugging) return; /* no output if not asked for */
-
- if (type)
- fprintf (stdout, "%s", instr);
- else
- fprintf (stdout, "%s instruction not implimented\n", instr);
- return;
- }
-
- /*--------------------------------------*/
-
- void new_plot ( void )
- {
-
- dirty_plot = 0; /* plot is clean (not plotted on) */
- return;
- }
-
- /*--------------------------------------*/
-
- int plotted_on (int plot_flag)
- {
-
- if (plot_flag > 0)
- dirty_plot = 1; /* mark plot as plotted on */
- return (dirty_plot);
- }
-
- /*--------------------------------------*/
-
- void circle (FILE * infile)
- {
- double ang, ang2, radius, val2, x_1, y_1;
- unsigned char c2;
- int segs;
-
- DB(printf ("CI\n");)
-
- if (!get_val (infile, &radius))
- {
- print_string ("CI: radius not specified\n");
- return; /* error: no param's */
- }
-
- ang2 = val2 = DEF_CHORD; /* default chord angle or deviation for circle/arc */
- if ( get_val (infile, &val2))
- {
- val2 = fabs (val2); /* only positive values allowed */
- if (chord_type == ANG || val2 == 0.0) /* using angles, not deviations */
- {
- if (val2 == 0.0) val2 = DEF_CHORD; /* set default chord angle or deviation */
- ang2 = MIN (MAX_CHORD, (MAX (val2, MIN_CHORD)));
- }
- else /* chord angle determined by deviation of segments from circle radius */
- { /* at this point, val2 is length in current units, not angle in degrees */
- if (val2 > 2.0 * radius) val2 = 2.0 * radius; /* limit deviation: resulting chord angle < 180 deg. */
- ang2 = acos ( (radius - val2) / radius) * RAD_2_DEG;
- }
- }
- segs = (int) (360.0 / ang2 + 0.5); /* # segments in 360 deg. */
- /* sign of 'segs' changes direction of arc () */
- DB (printf ("CI: radius = %lf, chord = %lf, # segments = %d\n", radius, ang2, segs);)
- where (&x_1, &y_1);
- arc (radius, segs, 0.0, 360.0); /* circle with l segments */
- if (symbol_mode)
- {
- move (x_1, y_1);
- symbol_mark (symbol);
- }
- plotted_on (1); /* we drew something on this plot */
- return;
- }
-
- /*--------------------------------------*/
-
- void arc_3pt (FILE * infile, int type)
- { /* type 0 = absolute arc, type 1 = relative arc */
- double ma, mb, ba, bb, x_1, y_1, xi, yi, xe, ye;
- double dax, day, dbx, dby, xc, yc, ang_e, ang_i;
- double start_ang, stop_ang, radius, ang2, val5;
- int segs, cw;
-
- DB (if (type == RELATIVE) printf ("AR\n"); else printf ("AT\n");)
- if (!get_xy (infile, &xi, &yi))
- {
- if (type == RELATIVE)
- print_string ("AR: missing Xi or Yi value\n");
- else
- print_string ("AT: missing Xi or Yi value\n");
- return;
- }
- if (!get_xy (infile, &xe, &ye))
- {
- if (type == RELATIVE)
- print_string ("AR: missing Xe or Ye value\n");
- else
- print_string ("AT: missing Xe or Ye value\n");
- return;
- }
-
- where (&x_1, &y_1); /* current position */
- if (type == RELATIVE) /* relative arc in 3 pts */
- {
- xe += x_1;
- ye += y_1;
- xi += x_1;
- yi += y_1; /* convert from offsets to abs coordinates */
- }
-
- dax = xe - x_1;
- day = ye - y_1; /* delta-x, -y from ref. to end pt. */
- dbx = xi - xe;
- dby = yi - ye; /* delta-x, -y from end pt. to intermediate pt. */
-
- DB (printf ("P1: (%lf, %lf) Pi: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xi, yi, xe, ye);)
- DB (printf ("fabs (day) = %lf, fabs(dby) = %lf\n", fabs(day), fabs(dby));)
-
- if ( fabs (day) < FLT_EPSILON) /* P1, Pe horizontal or same */
- { /* FLT, not DBL: more conservative */
- DB (printf ("fabs (day) < FLT_EPSILON\n");)
- xc = x_1 + dax / 2; /* equation of vertical line */
- if (fabs (dby) < FLT_EPSILON || fabs (dax) < FLT_EPSILON)
- { /* all pts horizontal */
- DB (printf ("vertical or straight line curve\n");)
- if (symbol_mode)
- {
- move (x_1, y_1);
- symbol_mark (symbol);
- }
- draw (xi, yi); /* draw intermediate pt in case end & start same */
- draw (xe, ye); /* this is the curve */
-
- plotted_on (1); /* we drew something on this plot */
- return;
- }
- mb = -dbx / dby; /* slope of line normal to PePi */
- bb = (ye + dby / 2) - mb * (xe + dbx / 2); /* now have b-part of line equations */
- yc = mb * xc + bb;
- }
- else
- { /* FLT, not DBL: more conservative */
- if (fabs (dby) < FLT_EPSILON) /* Pe, Pi horizontal or same */
- {
- DB (printf ("fabs (dby) < FLT_EPSILON\n");)
- xc = xe + dbx / 2; /* equation of vertical line */
- if (fabs (day) < FLT_EPSILON || fabs (dbx) < FLT_EPSILON)
- { /* all pts horizontal or Pe == Pi */
- DB (printf ("horizontal or straight line curve\n");)
- if (symbol_mode)
- {
- move (x_1, y_1);
- symbol_mark (symbol);
- }
- draw (xi, yi); /* draw intermediate pt in case end & start same */
- draw (xe, ye); /* this is the curve */
- plotted_on (1); /* we drew something on this plot */
- return;
- }
- ma = -dax / day; /* slope of line normal to PiPe */
- ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
- yc = ma * xc + ba;
- }
- else
- {
-
- /* general case: can't handle dby = 0 or day = 0 */
- ma = -dax / day; /* slope of line normal to P1Pe */
- mb = -dbx / dby; /* slope of line normal to PePi */
-
- /* y_1 + day = y-value midway between y_1 and ye */
- /* x_1 + dax = x-value midway between x_1 and xe */
- /* ye + dby = y-value midway between ye and yi */
- /* xe + dbx = x-value midway between xe and yi */
- ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
- bb = (ye + dby / 2) - mb * (xe + dbx / 2); /* now have b-part of line equations */
-
- if (fabs (ma - mb) < FLT_EPSILON) /* that's right FLT, not DBL */
- { /* too small to prevent floating point overflow */
- DB (printf ("straight line curve\n");)
- if (symbol_mode)
- {
- move (x_1, y_1);
- symbol_mark (symbol);
- }
- draw (xi, yi); /* draw intermediate pt in case end & start same */
- draw (xe, ye); /* this is the curve */
- return;
- }
- xc = (bb - ba) / (ma - mb); /* now have x-center */
- yc = mb * xc + bb; /* can find yc using either line eqn. */
- }
- }
-
- DB (printf ("3-pt. arc: center at (%lf, %lf)\n", xc, yc);)
-
- radius = sqrt ((xc - x_1) * (xc - x_1) + (yc - y_1) * (yc - y_1));
-
- val5 = ang2 = DEF_CHORD;
-
- if (get_val (infile, &val5))
- {
- val5 = fabs (val5); /* only positive values allowed */
-
- /* note: if no tolerance is specified, the default is a
- chord ANGLE of 5 DEGREES, regardless of chord_type */
-
- if (chord_type == ANG || val5 == 0.0) /* using angles, not deviations */
- {
- if (val5 == 0.0) val5 = DEF_CHORD; /* set default chord angle */
- ang2 = MIN (MAX_CHORD, (MAX (val5, MIN_CHORD)));
- }
- else /* chord angle determined by deviation of segments from circle radius */
- { /* at this point, val5 is length in current units, not angle in degrees */
-
- if (val5 > 2.0 * radius) val5 = 2.0 * radius; /* limit deviation: resulting chord angle < 180 deg. */
- ang2 = acos ( (radius - val5) / radius) * RAD_2_DEG;
-
- /* note that this value is being left in radians (for now) */
- }
-
- }
-
- DB (printf ("P1: (%lf, %lf), Pc: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xc, yc, xe, ye);)
-
- start_ang = RAD_2_DEG * atan2 (y_1 - yc, x_1 - xc); /* angle from center to starting pt */
- stop_ang = RAD_2_DEG * atan2 (ye - yc, xe - xc); /* angle from center to stopping pt */
-
- DB (printf ("initial: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
-
- ang_e = RAD_2_DEG * atan2 (day, dax);
- ang_i = RAD_2_DEG * atan2 ( yi - y_1, xi - x_1); /* determine direction of arc */
-
- cw = 1; /* direction defaults to clockwise rotation */
-
- if (ang_e >= 0.0 && ang_i >= 0.0) /* resolve direction of arc by */
- cw = (ang_e < ang_i) ? 1 : 0; /* angle between ref. pt and other 2 pts */
- else
- {
- if (ang_e <= 0.0 && ang_i <= 0.0)
- cw = (ang_e < ang_i) ? 1 : 0;
- else
- {
- if (ang_e <= 0.0 && ang_i >= 0.0) /* first conflict */
- cw = (ang_i - ang_e <= 180.0) ? 1 : 0;
- else
- if (ang_e >= 0.0 && ang_i <= 0.0)
- cw = (ang_e - ang_i >= 180.0) ? 1 : 0;
- }
- }
- /* now we have determined which direction the arc is drawn (either cw or ccw) */
-
- switch (cw)
- {
- case 0: /* counter clockwise rotation */
- DB (printf ("counter-clockwise rotation\n");)
- if (start_ang >= 0.0 && stop_ang >= 0.0)
- {
- stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0; /* 1 */
- }
- else
- {
- if (start_ang <= 0.0 && stop_ang <= 0.0)
- {
- stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0; /* 2 */
- }
- else
- if (start_ang >= 0.0 && stop_ang <= 0.0) /* 4 */
- {
- stop_ang += 360.0;
- }
- }
- break;
- case 1: /* clockwise rotation */
- DB (printf ("clockwise rotation\n");)
- if (stop_ang >= 0.0 && stop_ang >= 0.0)
- {
- stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 1a */
- }
- else
- {
- if (start_ang <= 0.0 && stop_ang <= 0.0)
- {
- stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 2a */
- }
- else
- if (start_ang <= 0.0 && stop_ang >= 0.0) /* 4a */
- {
- stop_ang -= 360.0;
- }
- }
- break;
- default: break;
- }
-
- segs = (int) (fabs (start_ang - stop_ang) / ang2 + 0.5); /* # segments in "ang1" deg. */
- /* sign of 'segs' changes direction of arc () */
-
- DB (printf ("final: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
- DB (printf ("chord angle = %lf, # segments = %d\n", ang2, segs);)
-
- move (xc, yc); /* move to center of arc */
- arc (radius, segs ,start_ang, stop_ang);
-
- plotted_on (1); /* we drew something on this plot */
- return;
- }
-
- /*--------------------------------------*/
-
- void init_fills (void)
- { /* only need to initialize hatched & x-hatched fills */
-
- /* values for hatched fill and cross-hatched fill */
- /* for DEFAULTUNITS, spacing must be determined at the same time
- the fill is used for drawing since P1 & P2 could have changed */
-
- fill_code [HATCH].mode = fill_code [XHATCH].mode = DEFAULTUNITS;
-
- /* don't care about either opt1 or alt_opt1 since default unit sizes
- are calculated when they are drawn */
-
- fill_code [HATCH].opt1 = fill_code [XHATCH].opt1 = 0.0;
- fill_code [HATCH].alt_opt1 = fill_code [XHATCH].alt_opt1 = 0.0;
-
- fill_code [HATCH].opt2 = fill_code [XHATCH].opt2 = 0.0; /* angle = 0 */
-
- select_fill = DEFAULT_FILL; /* select default fill */
-
- return;
- }
-
- /*--------------------------------------*/
-
- void fix_hatch ( void )
- {
- /* don't care if scaling is on or off. This only affects hatch sizes
- when they are in user units and the scale changes */
-
- /* fill_code [].opt1 is in user units; fill_code [].alt_opt1 is in plotter units */
-
- if (fill_code [HATCH].mode == USERUNITS)
- fill_code [HATCH].alt_opt1 = fill_code [HATCH].opt1 / uu_2_pux;
- if (fill_code [XHATCH].mode == USERUNITS)
- fill_code [XHATCH].alt_opt1 = fill_code [XHATCH].opt1 / uu_2_pux;
- return;
- }
-
- /*--------------------------------------*/
-
- void fill_type (FILE *infile, int scaling )
- {
- double ftype, opt1, opt2;
- int f1, f2, type;
-
- f1 = f2 = 0; /* no arguments */
- opt1 = opt2 = 0.0;
- if (get_val (infile, &ftype))
- {
- /* test for invalid type */
- if (ftype < 1.0 || ftype > 11.0 || (ftype > 4.0 && ftype < 10.0))
- {
- while (get_val (infile, &opt1)); /* dump trailing arguments */
- return;
- }
- /* have one value argument */
- if (get_val (infile, &opt1))
- {
- f1 = 1; /* mark option #1 present */
- if (get_val (infile, &opt2))
- f2 = 1; /* mark option #2 present */
- }
- type = (int) ftype;
- type = (type > 4) ? (type - 6) : type - 1; /* shift range to 0 - 5 */
- }
- else
- {
- select_fill = type = DEFAULT_FILL; /* no fill-type -> default */
- /* save current fill-type in select_fill */
- fill_code [type].mode = DEFAULTUNITS;
- /* calculate size of units when fill is drawn */
- return;
- }
-
- switch (type)
- {
- case SOLID: /* solid fill: bidirectional */
- case SOLID1: /* solid_fill: unidirectional */
-
- select_fill = type; /* save current fill-type */
- /* no other information required */
- break;
-
- case HATCH: /* hatched fill */
- case XHATCH: /* crosshatched fill */
-
- select_fill = type; /* save current fill-type */
-
- if (f1) /* option #1 is present */
- {
- if (opt1 == 0.0) /* use default spacing */
- {
- fill_code [type].mode = DEFAULTUNITS;
- /* calculate size of units when fill is drawn */
- }
- else
- {
- fill_code [type].mode = PLOTTERUNITS; /* assume plotter units */
- /* save hatch x-spacing in plotter units */
- fill_code [type].alt_opt1 = opt1;
-
- /* don't care about size in user units */
- if (scaling == ON)
- {
- fill_code [type].mode = USERUNITS; /* correct assumption about units */
- fill_code [type].opt1 = opt1; /* user units value */
- fill_code [type].alt_opt1 = opt1 / uu_2_pux;
- /* save value of option #1 in plotter units */
-
- /* we do this because HPGL/2 demands that use units
- be frozen in equivalent plotter units if scaling is
- turned off */
- }
- }
-
- /* update angle value only if user supplied */
-
- if (f2) fill_code [type].opt2 = opt2;
- }
-
- break;
- case 4: select_fill = type; /* save current fill-type */
- /* shaded fill: not yet implimented */
- break;
- case 5: select_fill = type; /* save current fill-type */
- /* user defined fill: not yet implimented */
- break;
- default: print_string ("FT: Invalid fill type\n");
- break;
- }
-
- return;
- }
- /*--------------------------------------*/
-
- void draw_rect (FILE * infile, int type)
- { /* type 0 = absolute, type 1 = relative, 0x10 = absolute, filled,
- 0x11 = relative, filled */
- double xp, yp, xc, yc, x_sp, theta;
-
- DB ({if (type & FILLED_ABS) printf ("%s\n", (type & 1) ? "RR" : "RA");})
- DB ({if (!(type & FILLED_ABS)) printf ("%s\n", (type & 1) ? "ER" : "EA");})
- where (&xp, &yp); /* get current position */
- if (get_xy (infile, &xc, &yc))
- {
- /* calculate width and height for rectangle () function */
- if (type & 1) /* relative rect */
- {
- xc += xp;
- yc += yp; /* calculate opposite corner pos */
- }
- DB (printf ("Rectangle from (%lf, %lf) to (%lf, %lf)\n", xp, yp, xc, yc);)
- rectangle (xp, yp, xc, yc);
-
- plotted_on (1); /* mark plot as dirty */
- if (type & 0x10)
- {
- DB (printf ("filled rectangle: select_fill = %d\n", select_fill);)
- if (select_fill != HATCH && select_fill != XHATCH)
- {
- if (select_fill == SOLID || select_fill == SOLID1)
- {
- solid_rect ( xp, yp, xc, yc);
- return;
- }
- else
- return; /* unsupported fill type */
- }
- theta = fill_code [select_fill].opt2; /* theta */
-
- /* get current hatch spacing in plotter units */
- /* for default units, calculate size now */
-
- DB (printf ("rectangle: theta = %lf, fill_code[select_fill].mode = %d\n", \
- theta, fill_code [select_fill].mode);)
- switch (fill_code [select_fill].mode)
- {
- case DEFAULTUNITS:
- x_sp = 0.01 * sqrt ( (p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
- break;
- case PLOTTERUNITS:
- case USERUNITS:
- x_sp = fill_code [select_fill].alt_opt1;
- /* x-spacing is in plotter units */
- break;
- default: break;
- }
-
- if (scaling == ON) /* convert to plotter units */
- {
- plotter_units (&xp, &yp);
- plotter_units (&xc, &yc); /* corner coordinates in plotter units */
- }
- DB (printf ("draw_rect: filled rect: (xp, yp) = (%lf, %lf), (xc, yx) = (%lf, %lf)\n",\
- xp, yp, xc, yc);)
- fill_rect (xp, yp, xc, yc, x_sp, theta);
- if (select_fill == XHATCH) /* if cross-hatch, draw crossing hatch at theta + 90 */
- fill_rect (xp, yp, xc, yc, x_sp, theta + 90.0);
- }
- return;
- }
-
- if (type & 0x10) /* filled */
- {
- if (type & 1)
- print_string ("ER: missing argument\n");
- else
- print_string ("EA: missing argument\n");
- }
- else
- {
- if (type & 1)
- print_string ("RR: missing argument\n");
- else
- print_string ("RA: missing argument\n");
- }
-
- return;
- }
-
- /*--------------------------------------*/
-
- static void fill_rect (double x_1, double y_1, double x_2, double y_2, double x_sp, double theta)
- { /* x_sp, x_1, x_2, y_1, y_2 all in plotter units */
- double ymin, ymax, xmin, xmax;
- double xd1, yd1, xd2, yd2, ac_x, ac_y, x_off, xh;
- double yh, yi, xi, y_off, xlast, ylast, etan, ecot, theta_r;
- int n, sector;
-
- get_anchor (&ac_x, &ac_y); /* get anchor corner in plotter units */
-
- xmin = x_1;
- ymin = y_1;
- xmax = x_2;
- ymax = y_2;
-
- DB (printf ("hatch_fill: x_sp = %lf, theta = %lf\n", x_sp, theta);)
-
- theta = fmod (theta, 180.0);
- theta_r = theta / RAD_2_DEG;
-
- if (theta < 90.0)
- { /* sectors 1,5 */
- if (theta < 45.0)
- {
- sector = 1;
- yi = (x_1 - ac_x) * tan (theta_r) + ac_y;
- yh = x_sp / cos (theta_r); /* this fails at theta = 90 */
-
- y_off = fmod (y_2 - yi, yh); /* get distance below top edge for starting point */
-
- y_1 = ymax - y_off;
-
- if (y_1 > ymax) y_1 -= yh; /* check case of yi > y_1 */
- if (y_1 < ymin) y_1 += yh; /* check case of yi < y_1 */
- y_2 = y_1 + (xmax - xmin) * tan (theta_r);
- }
- else
- { /* sectors 2, 6 */
- sector = 2;
- xi = (y_1 - ac_y) * cot (theta_r) + ac_x;
- xh = x_sp / sin (theta_r); /* this fails at theta = 0 */
-
- x_off = fmod (x_2 - xi, xh); /* get distance inside of right edge for starting point */
-
- x_1 = xmax - x_off;
- if (x_1 > xmax) x_1 -= xh; /* check case of xi > x_1 */
- if (x_1 < xmin) x_1 += xh; /* check case of xi < x_1 */
- x_2 = x_1 + (ymax - ymin) * cot (theta_r);
- }
-
- }
- else /* sectors 4,8 */
- {
- if (theta > 135.0)
- {
- sector = 4;
- yi = (x_2 - ac_x) * tan (theta_r) + ac_y;
- yh = - x_sp / cos (theta_r); /* this fails at theta = 90 */
-
- /* get distance above bottom edge for starting point */
- y_off = fmod (y_2 - yi, yh);
-
- y_1 = ymax - y_off;
- if (y_1 > ymax) y_1 -= yh; /* check case of yi > y_1 */
- if (y_1 < ymin) y_1 += yh; /* check case of yi < y_1 */
- y_2 = y_1 - (xmax - xmin) * tan (theta_r);
- /* tan (theta) < 0 for 90 <= theta < 180 */
-
- xmin = x_2;
- xmax = x_1;
- }
- else
- { /* sectors 3,7 */
- sector = 3;
- xi = (y_2 - ac_y) * cot (theta_r) + ac_x;
- xh = x_sp / sin (theta_r); /* this fails at theta = 0 */
-
- x_off = fmod (x_2 - xi, xh); /* get distance inside of right edge for starting point */
-
- x_1 = xmax - x_off;
-
- if (x_1 > xmax) x_1 -= xh; /* check case of xi > x_1 */
- if (x_1 < xmin) x_1 += xh; /* check case of xi < x_1 */
- x_2 = x_1 - (ymax - ymin) * cot (theta_r);
-
- ymax = y_1;
- ymin = y_2;
- }
-
- }
-
-
- if (x_sp == 0.0) return; /* no point in wasting time */
-
- where (&xlast, &ylast); /* get current position in current units */
-
- n = 0; /* emergency break-out counter */
-
- if (sector == 1 || sector == 4)
- {
- etan = tan (theta_r);
- while (y_2 > ymin && n < 2048) /* this loop only works for 0 <= theta < 90 */
- {
- ++n;
- xd1 = xmin;
- yd1 = y_1;
- xd2 = xmax;
- yd2 = y_2;
-
- if (yd2 > ymax)
- {
- yd2 = ymax;
- xd2 = xmin + (yd2 - y_1) / etan;
- } /* never reach this case if theta == 0 since */
- /* y_1 == y_2 and y_1 < ymax */
-
- if (yd1 < ymin)
- {
- yd1 = ymin;
- xd1 = xmin + (ymin - y_1) / etan;
- } /* never reach this case if theta == 0 since y_2 == y_1 */
- /* and loop begins with y_1 >= ymin */
-
- if (scaling == ON) /* convert to user units */
- {
- user_units (&xd1, &yd1);
- user_units (&xd2, &yd2);
- }
-
- move (xd1, yd1);
- draw (xd2, yd2);
- y_1 -= yh;
- y_2 -= yh;
- }
- }
- else /* sectors 2, 3 */
- {
- ecot = cot (theta_r);
- while (x_2 > xmin && n < 2048) /* this loop decrements x sizes */
- {
- ++n;
- xd1 = x_1;
- yd1 = ymin;
- xd2 = x_2;
- yd2 = ymax;
-
- if (xd2 > xmax)
- {
- xd2 = xmax;
- yd2 = ymin + (xd2 - x_1) / ecot;
- } /* never reach this case if theta == 0 since */
- /* x_1 == x_2 and x_1 < xmax */
-
- if (xd1 < xmin)
- {
- xd1 = xmin;
- yd1 = ymin + (xmin - x_1) / ecot;
- } /* never reach this case if theta == 0 since y_2 == y_1 */
- /* and loop begins with x_1 >= xmin */
-
- if (scaling == ON) /* revert to user units for drawing */
- {
- user_units (&xd1, &yd1);
- user_units (&xd2, &yd2);
- }
-
- move (xd1, yd1);
- draw (xd2, yd2);
- x_1 -= xh;
- x_2 -= xh;
- }
- }
-
- move (xlast, ylast); /* return to original position */
- }
-
- /*-------------------------------------*/
-
- static void solid_rect (double x_1, double y_1, double x_2, double y_2)
- { /* draw solid filled rectangles w/o rotation */
- /* passed parameters are in current units */
- int x, y, page, c1, c2;
- struct scrn_pixel__ pix1, pix2;
-
- DB (printf ("solid_fill: from (%lf,%lf) to (%lf,%lf)\n", x_1, y_1, x_2, y_2);)
-
- /* because there is no filled rectangle in the graphix library, we are
- force to make our own here, and call the line drawing portion of the
- graphix library directly. That gives the best drawing speed and makes
- it possible to prevent line overlap at the pixel level. To do
- this, we need to know the clip borders in the current units. We can
- use pmap () to retrieve the pixel coordinates of the rectangle corners.
- The clipping code used here is a modified Cohen-Sutherland coded clipper.
- It returns the clip end-points of a horizontal and a vertical line. If
- the x or y end-points are both outside the clip border, then the
- entire rectangle must be outside the clip border, and there is nothing
- to draw. */
-
- page = 0; /* used by pc_wrt_line (): current graphix page */
-
-
- /* get pixel coordinates */
- pmap (x_1, y_1, (struct scrn_pixel__ _far *) &pix1);
- pmap (x_2, y_2, (struct scrn_pixel__ _far *) &pix2);
-
- pix1.yp = __gr_msc__.max_y_dot - pix1.yp; /* pmap () returns true pixel coordinates */
- pix2.yp = __gr_msc__.max_y_dot - pix2.yp; /* map to origin in lower left corner */
-
- DB (printf ("solid_fill: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
-
- c1 = code (pix1.xp, pix1.yp);
- c2 = code (pix2.xp, pix1.yp);
-
- DB (printf ("c1 = %d, c2 = %d\n", c1, c2);)
-
- if ( c1 & (4 | 8) ) /* test x-coordinates */
- {
- if ( c1 & 0x8 ) /* x_1 < clip_xmin */
- {
- if (c2 & 0x8) /* x_2 < clip_xmin */
- return; /* both x-coords outside clip border */
- pix1.xp = hpgl_clip.xmin;
- }
- else if ( c1 & 0x4 ) /* x_1 > clip_xmax */
- {
- if (c2 & 0x04) /* x_2 > clip_xmax */
- return; /* both x-coords outside clip border */
- pix1.xp = hpgl_clip.xmax;
- }
- }
-
- if ( c2 ) /* test 2nd x-coordinate */
- {
- if ( c2 & 0x8 ) /* x_2 < clip_xmin */
- { /* already tested x_1 */
- pix2.xp = hpgl_clip.xmin;
- }
- else if ( c2 & 0x4 ) /* x_2 > clip_xmax */
- { /* already tested x_1 */
- pix2.xp = hpgl_clip.xmax;
- }
- }
-
- c1 = code (pix1.xp, pix1.yp);
- c2 = code (pix1.xp, pix2.yp);
- DB (printf ("c1 = %d, c2 = %d\n", c1, c2);)
-
- if ( c1 & (1 | 2) )
- {
- if ( c1 & 0x2 ) /* y_1 < clip_ymin */
- {
- if (c2 & 0x2) /* y_2 < clip_ymin */
- return;
- pix1.yp = hpgl_clip.ymin;
- }
- else if ( c1 & 0x1 ) /* y_1 > clip_ymax */
- {
- if (c2 & 0x1) /* y_2 > clip_ymax */
- return;
- pix1.yp = hpgl_clip.ymax;
- }
- }
-
- if ( c2 ) /* test 2nd y-coordinate */
- {
- if ( c2 & 0x2 ) /* y_2 < clip_ymin */
- { /* already tested y_1 */
- pix2.yp = hpgl_clip.ymin;
- }
- else if ( c2 & 0x1 ) /* y_2 > clip_ymax */
- { /* already tested y_1 */
- pix2.yp = hpgl_clip.ymax;
- }
- }
-
- DB (printf ("solid_fill: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
-
- /* now limit pixel value to screen size */
- pix1.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix1.xp)));
- pix1.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix1.yp)));
- pix2.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix2.xp)));
- pix2.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix2.yp)));
-
- DB (printf ("solid_fill: limited (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
-
- if (pix1.yp > pix2.yp)
- {
- y = pix1.yp;
- pix1.yp = pix2.yp;
- pix2.yp = y;
- }
-
- for (y = pix1.yp; y <= pix2.yp; ++y) /* draw the solid rectangle */
- {
- pc_wrt_line (page, pix1.xp, y, pix2.xp, y, my_pen);
- } /* my_pen = internal pen color */
-
- return;
- }
-
-
- /*-------------------------------------*/
-
- /*
- | 1 |
- | |
- --------+-------------+---------
- | |
- 8 | OK | 4
- | |
- --------+-------------+---------
- | |
- | 2 |
-
- */
-
- static int code (int x, int y) /* return clipping code */
- {
- int clip_code;
-
- clip_code = 0;
-
- if (x < hpgl_clip.xmin) clip_code = 8;
- else if (x > hpgl_clip.xmax) clip_code = 4;
-
- if (y < hpgl_clip.ymin) clip_code |= 2;
- else if (y > hpgl_clip.ymax) clip_code |= 1;
-
- return (clip_code);
- } /* returned code: (x < xmin:x > xmax:y < ymin:y > ymax) */
-
- /*-------------------------------------*/
-
- static double cot ( double theta )
- { /* valid from 0 to 180 degrees */
- double a;
-
- a = cos (theta);
- return ( a * sqrt ( 1.0 - a * a));
- }
-
- /*--------------------------------------*/
-
- void chord_t (FILE * infile)
- {
- double x;
-
- if (get_val (infile, &x))
- {
- if (x == 1.0)
- {
- chord_type = LENGTH;
- return;
- }
- if (x != 0.0)
- {
- print_string ("CT: invalid argument\n");
- return;
- }
- }
- chord_type = ANG; /* chord type in degree's */
- return;
- }
-
- /*--------------------------------------*/
-
- void set_clip (double x_1, double x_2, double y_1, double y_2)
- {
- struct scrn_pixel__ pix1, pix2;
- double px1, px2, py1, py2, tmp;
-
- px1 = p1x;
- px2 = p2x;
- py1 = p1y;
- py2 = p2y;
-
- DB (printf ("set_clip: clip from (%18.11lf,%18.11lf) to (%18.11lf,%18.11lf)\n", x_1, y_1, x_2, y_2);)
- DB (printf ("set_clip: hard clip: (p1x, p1y) = (%lf,%lf) to (p2x, p2y) = (%lf,%lf)\n", p1x, p1y, p2x, p2y);)
-
- /* check against P1/P2 window */
- if (scaling == ON)
- { /* get user units for "hard clip" border */
- user_units (&px1, &py1);
- user_units (&px2, &py2);
- }
-
- /* limit clipping border to P1/P2 border */
- /* this will prevent drawing outside the P1/P2 border when */
- /* P1/P2 < paper size and clipping window > P1/P2 border */
- /* exchange x_1, x_2 and y_1, y_2 if P1/P2 exchanged */
-
- if (p1x < p2x)
- {
- x_1 = MAX (px1, x_1);
- x_2 = MIN (px2, x_2);
- }
- else /* P1/P2 exchanged */
- {
- tmp = MAX (px2, x_2);
- x_2 = MIN (px1, x_1);
- x_1 = tmp;
- }
-
- if (p1y < p2y)
- {
- y_1 = MAX (py1, y_1);
- y_2 = MIN (py2, y_2);
- }
- else /* P1/P2 exchanged */
- {
- tmp = MAX (py2, y_2);
- y_2 = MIN (py1, y_1);
- y_1 = tmp;
- }
-
- DB (printf ("set_clip: clip from (%lf,%lf) to (%lf,%lf)\n", x_1, y_1, x_2, y_2);)
- clip (x_1, x_2, y_1, y_2); /* clipping limited to P1/P2 window */
-
- /* get pixel coordinates */
- pmap (x_1, y_1, (struct scrn_pixel__ _far *) &pix1);
- pmap (x_2, y_2, (struct scrn_pixel__ _far *) &pix2);
-
- DB (printf ("set_clip: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
-
- /* now limit pixel value to screen size */
- pix1.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix1.xp)));
- pix1.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix1.yp)));
- pix2.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix2.xp)));
- pix2.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix2.yp)));
-
- DB (printf ("set_clip: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
-
- hpgl_clip.xmin = pix1.xp;
- hpgl_clip.xmax = pix2.xp;
-
- hpgl_clip.ymin = __gr_msc__.max_y_dot - pix1.yp;
- hpgl_clip.ymax = __gr_msc__.max_y_dot - pix2.yp; /* compensate for origin in LL corner */
- /* save clip border in pixels for solid_fill () */
-
- DB (printf ("set_clip: hardclip (pixel) (%d,%d) to (%d,%d)\n", hpgl_clip.xmin, hpgl_clip.ymin, hpgl_clip.xmax, hpgl_clip.ymax);)
-
- return;
- }
-
- /*--------------------------------------*/
-